## 处理地图生成工作
## 生成算法, 递归分支 + 权重法 + 随机数
## boss房间一定在最后, 出生点四周一定有房间
## 房间之间的通道一定要连通, 不能出现有门无房间, 有房间无门的情况
## 每个房间必须都是可到达的, 不能出现断开的房间
## 继承: Node
class_name GenerateMap extends Node

enum {TOP = 0, RIGHT = 1, BOTTOM = 2, LEFT = 3}
enum {FIGHT = 0, REWARD = 1, STORE = 2, BOSS = 3}

const SCREEN_SIZE = Vector2(480, 272)
const VECTOR_LEFT = Vector2(-1, 0) * SCREEN_SIZE
const VECTOR_RIGHT = Vector2(1, 0) * SCREEN_SIZE
const VECTOR_TOP = Vector2(0, -1) * SCREEN_SIZE
const VECTOR_BOTTOM = Vector2(0, 1) * SCREEN_SIZE
const HOME = Vector2.ZERO
const deep := 4

const boosRoom = [
	"res://Room/tscn/MettatonRoom.tscn"
]

const storeRoom = [
	"res://Room/tscn/StoreRoom.tscn"
]

const fightRoom = [
	"res://Room/tscn/GrassRoom.tscn",
	"res://Room/tscn/StoneRoom.tscn"
]

const rewardRoom = [
	"res://Room/tscn/GrassRoom.tscn"
]

var mapConfig = []
var rooms = {}
var room_positions = []
var connections = []
	
	
## 如果生成的房间没有boss, 就一直生成
func generate_map_exsit_boss():
	while true:
		var mapConfig = generate_map()
		if str(mapConfig).contains("\"type\": 3"):
			return mapConfig
		
## @param success 接收回调函数
func generate_map():
	# 初始化存储结构
	rooms.clear()
	room_positions.clear()
	connections.clear()
	mapConfig.clear()
	
	# 创建初始中心房间（必须存在）
	var start_room = create_room(HOME, FIGHT)
	start_room.door = [TOP, RIGHT, BOTTOM, LEFT]
	mapConfig.append(start_room)
	
	# 强制生成主房间四周的房间
	var required_positions = [
		HOME + VECTOR_TOP,    # 上
		HOME + VECTOR_RIGHT, # 右
		HOME + VECTOR_BOTTOM,# 下
		HOME + VECTOR_LEFT   # 左
	]
	
	for pos in required_positions:
		var room = create_room(pos, get_primary_room_type())
		# 设置返回中心房间的门
		var return_dir = get_direction_to_home(pos)
		room.door.append(return_dir)
		mapConfig.append(room)
		# 连接中心房间
		connect_rooms(HOME, pos, opposite_dir(return_dir))
	
	# 从四个基础房间开始生成分支
	for pos in required_positions:
		generate_branch(pos, deep)
	
	# 添加特殊房间
	add_special_rooms()
	
	return mapConfig

func get_primary_room_type() -> int:
	# 基础房间类型：80%战斗，20%奖励
	return FIGHT if randf() < 0.8 else REWARD

func create_room(pos: Vector2, type: int) -> Dictionary:
	var room = {
		"type": type,
		"position": pos,
		"door": [],
		"source": get_random_room(type)
	}
	rooms[pos] = room
	room_positions.append(pos)
	return room

func generate_branch(current_pos: Vector2, depth: int) -> void:
	if depth <= 0: 
		return
		
	var directions = [TOP, RIGHT, BOTTOM, LEFT]
	directions.shuffle()
	
	for dir in directions:
		var new_pos = current_pos + get_vector(dir)
		# 跳过已存在房间和中心房间
		if rooms.has(new_pos) || new_pos == HOME:
			continue
			
		if randf() < 0.8:  # 80%概率生成分支
			var room_type = FIGHT
			if randf() < 0.2:  # 20%概率奖励房
				room_type = REWARD
				
			var new_room = create_room(new_pos, room_type)
			connect_rooms(current_pos, new_pos, dir)
			mapConfig.append(new_room)
			
			generate_branch(new_pos, depth - 1)

func connect_rooms(pos1: Vector2, pos2: Vector2, dir: int) -> void:
	var opposite_dir = (dir + 2) % 4
	if dir not in rooms[pos1].door:
		rooms[pos1].door.append(dir)
	if opposite_dir not in rooms[pos2].door:
		rooms[pos2].door.append(opposite_dir)
	connections.append({"from": pos1, "to": pos2})

func add_special_rooms() -> void:
	# 添加商店（至少距离中心2屏）
	var store_pos = find_furthest_room(2)
	if store_pos != null:
		rooms[store_pos].type = STORE
		rooms[store_pos].source = get_random_room(STORE)
	
	# 添加BOSS房, 最深层才有boss
	var boss_pos = find_furthest_room(deep)
	if boss_pos != null:
		rooms[boss_pos].type = BOSS
		rooms[boss_pos].source = get_random_room(BOSS)
		# 保留第一个出口方向
		if rooms[boss_pos].door.size() > 0:
			rooms[boss_pos].door = [rooms[boss_pos].door[0]]

func find_furthest_room(min_distance: int):
	var candidates = []
	for pos in room_positions:
		if pos.distance_to(HOME) > min_distance * SCREEN_SIZE.x && pos.distance_to(HOME) > min_distance * SCREEN_SIZE.y:
			candidates.append(pos)
	return candidates[randi() % candidates.size()] if candidates else null

func get_vector(dir: int) -> Vector2:
	match dir:
		TOP: return VECTOR_TOP
		RIGHT: return VECTOR_RIGHT
		BOTTOM: return VECTOR_BOTTOM
		LEFT: return VECTOR_LEFT
	return Vector2.ZERO

func get_direction_to_home(pos: Vector2) -> int:
	var offset = pos - HOME
	match offset:
		VECTOR_TOP: return BOTTOM
		VECTOR_RIGHT: return LEFT
		VECTOR_BOTTOM: return TOP
		VECTOR_LEFT: return RIGHT
		
	return -1

func opposite_dir(dir: int) -> int:
	return (dir + 2) % 4

func get_random_room(type: int) -> Resource:
	match type:
		BOSS: return load(boosRoom[randi() % boosRoom.size()])
		STORE: return load(storeRoom[randi() % storeRoom.size()])
		REWARD: return load(rewardRoom[randi() % rewardRoom.size()])
		FIGHT: return load(fightRoom[randi() % fightRoom.size()])
	return null
